﻿
using Base.Common.entity;
using hlog;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Web;

namespace Base.Common.httpServer {
    public class HttpServer {
        private TcpListener _listeners;
        private volatile bool _isInit;
        private IMServer mServer;
        public HttpServer(int port) {
            var localEp = new IPEndPoint(IPAddress.Any ,port);
            try {
                _listeners = new TcpListener(IPAddress.Any ,port);
                _listeners.Start(5000);
                _isInit = true;
                _listeners.BeginAcceptTcpClient(AcceptAsync_Async ,null);
                mServer = GuidangFactray.getDal<IMServer>();
            } catch( Exception e ) {
                LoggerCommon.error(port + "端口监听异常" ,e);
                Dispose();
            }
        }
       
        private void AcceptAsync_Async(IAsyncResult iar) {
            _listeners.BeginAcceptTcpClient(AcceptAsync_Async ,null);

            TcpClient client = _listeners.EndAcceptTcpClient(iar);
            NetworkStream networkStream = client.GetStream();
            BufferedStream _inputStream = new BufferedStream(networkStream);
            Processer p = new Processer();
            try {
                var res = p.Process(_inputStream  ,networkStream);
                if( res.code == 502 ) {
                    fileBack(networkStream ,p);
                } else if( res.data is FileStreamResult ) {
                    downFile(networkStream ,( FileStreamResult ) res.data);


                } else {
                    String value = JsonHelper.mySerializeObject(res);
                    if( p.controlName != null && p.httpMethod != "OPTIONS" ) {
                        log(p.controlName ,client.Client.RemoteEndPoint.ToString() ,p.HttpUrl ,JsonHelper.mySerializeObject(p.param) ,value);
                    }
                    WriteSuccess(networkStream ,value);
                }

            } finally {
                try {
                    networkStream.Flush();
                } catch { }
                try {
                    _inputStream.Dispose();
                } catch { }
                try {
                    networkStream.Dispose();
                } catch { }
                try {
                    client.Close();
                } catch { }
                _inputStream = null;
                networkStream = null; // bs = null;      

               
            }
        }
        void log(ControlName controlName ,String ip ,String url ,String param ,String value) {
            if( BaseConfig.httpServerLog ) {
                HttpServerLog log = new HttpServerLog();
                log.ip = ip;
                log.url = url;
                log.param = param;
                log.result = value;
               
                if( controlName != null ) {
                    log.urlName = controlName.Name;
                } else {
                    log.urlName = url;
                }
         
                log.user = CookieHelper.LoginName();
                mServer.save(log);
            }
        }

        void downFile(NetworkStream networkStream ,FileStreamResult r) {
            try {
                Stream fileStream = r._stream;
                byte[] b = null;
                int length = 0;
                try {
                    length = ( int ) fileStream.Length;
                    b = new byte[length];
                    fileStream.Read(b ,0 ,length);
                } finally {
                    if( fileStream != null ) {
                        fileStream.Close();
                    }

                }
                Write(networkStream ,"HTTP/1.0 200 OK");
                Write(networkStream ,"Content-Type:application/octet-stream");
                Write(networkStream ,"Connection: keep-alive");
                Write(networkStream ,"Content-Length:" + length);
                Write(networkStream ,"Vary: Accept-Encoding");
                Write(networkStream ,"Accept - Ranges: bytes");
                Write(networkStream ,"Content-Disposition:" + "attachment; filename=" + r._fileName);
                Write(networkStream ,"Server:gk 4.16");
                networkStream.Write(new byte[] { 10 } ,0 ,1);
                networkStream.Write(b ,0 ,length);
                networkStream.Flush();
            }  catch (Exception ex) {
                LoggerCommon.error("downFile回复失败" ,ex);
            }

}

        void fileBack(NetworkStream networkStream  ,Processer p) {
            String path = p.HttpUrl;
            if( String.IsNullOrEmpty(path) || path == "/" ) {
                path = "/index.html";
            }
            try {
                
                FileStream fileStream = null;
                byte[] b = null;
                int length = 0;
                try {
                    fileStream = File.OpenRead("dist/" + path);
                    length = ( int ) fileStream.Length;
                    b = new byte[length];
                    fileStream.Read(b ,0 ,length);
                } finally {
                    if( fileStream != null ) {
                        fileStream.Close();
                    }

                }
                Write(networkStream ,"HTTP/1.0 200 OK");
                Write(networkStream ,"Content-Type:" + getType(path));
                Write(networkStream ,"Connection: keep-alive");
                Write(networkStream ,"Content-Length:" + length);
                Write(networkStream ,"Vary: Accept-Encoding");
                Write(networkStream ,"Accept - Ranges: bytes");
                Write(networkStream ,"Server:gk 4.16");
                networkStream.Write(new byte[] { 10 } ,0 ,1);
                networkStream.Write(b ,0 ,length);
                networkStream.Flush();
            } catch( Exception ex ) {
                LoggerCommon.error("fileBack回复失败"+ path ,ex);
            }


        }
        public void WriteSuccess(NetworkStream networkStream ,String value) {
            try {
                Write(networkStream ,"HTTP/1.0 200 OK");
                Write(networkStream ,"Content-Type: application/json");
                Write(networkStream ,"Connection: close");
                Write(networkStream ,"Access-Control-Allow-Origin: *");
                Write(networkStream ,"Access-Control-Allow-Headers: Content-Type,X-Token,token");
                Write(networkStream ,"Access-Control-Allow-Credentials: true");
                Write(networkStream ,"Access-Control-Allow-Methods: GET,POST,OPTIONS");
                Write(networkStream ,"Cache-Control:no-cache");
                Write(networkStream ,"Server:gk 4.16");
                Write(networkStream ,"");
                Write(networkStream ,value);
            } catch( Exception ex ) {
                LoggerCommon.error("WriteSuccess回复失败"+ value ,ex);
            }



        }
        public void Dispose() {
            if( _isInit ) {
                _isInit = false;
                Dispose(true);
                GC.SuppressFinalize(this);
            }
        }
        protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool flag1) {
            if( flag1 ) {
                if( _listeners != null ) {
                    try {
                        _listeners.Stop();
                        _listeners = null;
                    } catch {
                    }
                }
            }
        }

        String getType(String url) {
            if( url.EndsWith("html") ) {
                return "text/html; charset=UTF-8";
            }
            if( url.EndsWith("htm") ) {
                return "text/html; charset=UTF-8";
            }
            if( url.EndsWith("css") ) {
                return "text/css; charset=UTF-8";
            }
            if( url.EndsWith("js") ) {
                return "application/x-javascript; charset=UTF-8";
            }
            if( url.EndsWith("ico") ) {
                return "application/x-ico";
            }

            if( url.EndsWith("woff") ) {
                return "application/font-woff";
            }

            return "application/octet-stream;charset:utf-8";
        }
       private  void Write(NetworkStream networkStream ,String d) {
            byte[] b = System.Text.Encoding.UTF8.GetBytes(d);
           
                networkStream.Write(b, 0, b.Length);
                networkStream.Write(new byte[] { 10 }, 0, 1);
           
            
           

        }
    }
   
}